﻿using GlobalObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using WCFServiceWebRole1.DataObjects;
using DataAccessLayer;
using System.Web;
using System.Web.Script.Serialization;
using WCFServiceWebRole1.Pusher;
using Microsoft.ApplicationServer.Caching;
using System.Xml.Serialization;
using System.IO;
using Microsoft.WindowsAzure.ServiceRuntime;


namespace WCFServiceWebRole1.Services
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "user" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select user.svc or user.svc.cs at the Solution Explorer and start debugging.




    //  string location = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri.ToString() + "/" + username;
    //  WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(new Uri(location));



    //Stream stm;
    //DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Device));
    //Device device = (Device)ser.ReadObject(stm);



    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
                 ConcurrencyMode = ConcurrencyMode.Single)]
    public class user : Iusers
    {
        #region Class variables

        public static DataCache myCache;
        public const string SUBSCRIBER_LIST = "SubscriberList";
        public static Uri servicePath = new Uri("http://uclwebservicetest.cloudapp.net/Services/users.svc/");
        public static Uri XmlFilePath = new Uri("http://uclwebservicetest.cloudapp.net/XMLConfigurationFiles/");
        public static UserEntity userEntity = new UserEntity();
        public static DeviceEntity deviceEntity = new DeviceEntity();
        public static SensorEntity sensorEntity = new SensorEntity();
        public static SubscriberList subscriberList = new SubscriberList();
        public static SharedEntity sharedEntity = new SharedEntity();
        public static TestimonialEntity testimonialEntity = new TestimonialEntity();
        public static ContactUsEntity contactUsEntity = new ContactUsEntity();
        public static SensorAccessTimeEntity monitorSensorEntity = new SensorAccessTimeEntity();
        public static NotificationEntity notificationEntity = new NotificationEntity();

        #endregion

        #region Cache

        public List<SubscriberRecord> SubscriberList
        {
            get
            {
                // Get Recent APIKeys from the cache
                myCache = WebRole.getCacheObject();
                var list = myCache.Get(SUBSCRIBER_LIST) as List<SubscriberRecord>;
                //if (list == null)
                //{
                //    //Creating Pusher subscription List
                //    List<SubscriberRecord> subList = new List<SubscriberRecord>();
                //    myCache.Add(SUBSCRIBER_LIST, subList);
                //    list = myCache.Get(SUBSCRIBER_LIST) as List<SubscriberRecord>;

                //}

                if (list != null && list.Count == 0)
                {
                    List<SubscriberRecord> newlist = subscriberList.getSubscriberList();
                    if (newlist != null)
                    {
                        foreach (var sub in newlist)
                        {
                            myCache.Put(SUBSCRIBER_LIST, sub);
                        }
                        list = myCache.Get(SUBSCRIBER_LIST) as List<SubscriberRecord>;
                    }
                    //else
                    //{
                    //    return null;
                    //}
                }
                return list;
            }
        }
        public void addSubcriber(SubscriberRecord subscriber)
        {
            //if (!SubscriberList.Contains(subscriber))
            //{
            subscriberList.addSubscriber(subscriber);

            DataCache cache = WebRole.getCacheObject();
            cache.Put(SUBSCRIBER_LIST, subscriber);
            // }
        }
        public void removeSubcriber(SubscriberRecord subscriber)
        {
            if (!SubscriberList.Contains(subscriber))
            {
                DataCache cache = WebRole.getCacheObject();
                List<SubscriberRecord> existinglist = SubscriberList;
                existinglist.Remove(subscriber);
                subscriberList.removeSubscriber(subscriber);
                cache.Remove(SUBSCRIBER_LIST);
                cache.Add(SUBSCRIBER_LIST, existinglist);
            }
        }

        #endregion

        #region Website Management

        public DeviceDiscovery getAllDevices(string iuserid)
        {
            DeviceDiscovery response = null;
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }
            try
            {
                if (!userEntity.checkUserIdDAL(userid))
                {
                    ErrorData errordata = new ErrorData("Invalid UserId");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
                }
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Invalid UserId" + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            try
            {
                response = deviceEntity.getAllAccessibleDevice_DAL(userid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Failed Devices Retrieval" + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            return response;
        }
        public string addcontactus(ContactUs data)
        {
            try
            {
                //add the details to the db
                contactUsEntity.insertToContactUs_DAL(data);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Operation Failed."+ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }
            return "success";
        }
        public string addTestimonial(Testimonial data)
        {
            try
            {
                //add the details to the db
                testimonialEntity.insertToTestimonials_DAL(data);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Operation Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }
            return "success";

        }
        public List<Testimonial> getTestimonials()
        {
            List<Testimonial> response;
            try
            {
                //get all the testimonials from the db
                response = testimonialEntity.getAllTestimonials_DAL();
              
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Operation Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }
            return response;
        }
        public Stream getConfigFile(int userid, int deviceid)
        {

            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            String FilePath = RoleEnvironment.GetLocalResource("XMLConfigurationFiles").RootPath + deviceid.ToString() + ".xml";
            Device deviceInfo;
            if (!File.Exists(FilePath))
            {
                try
                {
                    deviceInfo = deviceEntity.getDeviceById_DAL(userid, deviceid);

                    XmlSerializer writer = new XmlSerializer(typeof(Device));

                    using (FileStream file = File.OpenWrite(FilePath))
                    {
                        writer.Serialize(file, deviceInfo);
                    }

                }
                catch (Exception ex)
                {
                    ErrorData errordata = new ErrorData("Connection details cannot be null or empty." + ex.Message);
                    errordata.StackTrace = ex.StackTrace;
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
                }
            }

            WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";
            return File.OpenRead(FilePath);
        }
        #endregion

        #region User

        public UserDetailsResponse checkLogin(UserLoginContract credentials)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            int userid = 0;
            //Check if both username and password are present
            if (credentials.Username == null || credentials.Username == "" || credentials.Password == "" || credentials.Password == null)
            {
                ErrorData errordata = new ErrorData("Credentails are missing. Username or Password cannot be empty");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
            }

            //Check if the username and password matches
            try
            {

                userid = userEntity.checkLogin_DAL(credentials.Username, credentials.Password);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Login Failed" + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.PreconditionFailed);
            }
            //Check if the credentials were correct
            if (userid == 0)
            {
                ErrorData errordata = new ErrorData("Incorrect Username or Password");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Getting a user by ID        
            UserDetails item;
            //Retrieve user details from the repository 
            try
            {
                item = userEntity.getUserById_DAL(userid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Getting User Details Failed" + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.PreconditionFailed);
            }

            //Creating response message
            outResponse.StatusCode = HttpStatusCode.OK;
            Uri location = new Uri(servicePath, "user/" + item.Id.ToString());

            //Returning the response
            return new UserDetailsResponse()
            {
                resource = location,
                response = item
            };

        }
        public UserDetailsResponse getUserByUserId(string iuserid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            UserDetails item;
            //Retrieve user details from the repository 
            try
            {
                item = userEntity.getUserById_DAL(userid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Getting User Details Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.PreconditionFailed);
            }

            //Creating response message
            outResponse.StatusCode = HttpStatusCode.OK;
            Uri location = new Uri(servicePath, "user/" + item.Id.ToString());
            //Returning the response
            return new UserDetailsResponse()
            {
                resource = location,
                response = item
            };

        }
        public UserDetailsResponse addUser(User user)
        {
            User item;

            //Checking null values in the request
            if (user.LastName == null || user.Country == null || user.Email == null || user.FirstName == null || user.LastName == null ||
               user.Password == null || user.Title == null || user.Username == null || user.Purpose==null || user.Organisation ==null||
                user.LastName == "" || user.Country == "" || user.Email == "" || user.FirstName == "" || user.LastName == "" ||
                 user.Password == "" || user.Title == "" || user.Username == "" || user.Purpose == "" || user.Organisation == "" ||
                user.LastName == "null" || user.Country == "null" || user.Email == "null" || user.FirstName == "null" || user.LastName == "null" ||
                 user.Password == "null" || user.Title == "null" || user.Username == "null" || user.Purpose=="null" || user.Organisation =="null")
            {
                ErrorData errordata = new ErrorData("Some mandatory fields are missing in the submitted JSON");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the username already exists
            if (userEntity.checkUsernameDAL(user.Username))
            {
                ErrorData errordata = new ErrorData("Username already exists. Please try another username.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.PreconditionFailed);
            }

            //Perform the add user operation
            try
            {
                item = userEntity.addUser_DAL(user);
            }
            catch (ApplicationException ex)
            {
                ErrorData errordata = new ErrorData(ex.StackTrace);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }

            //Creating response message
            Uri location = new Uri(servicePath, "user/" + item.Id.ToString());
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            outResponse.StatusCode = HttpStatusCode.Created;

            //Returning response
            return new UserDetailsResponse()
            {
                resource = location,
                response = new UserDetails()
                {
                    Country = item.Country,
                    EmailAddress = item.Email,
                    FirstName = item.FirstName,
                    LastName = item.LastName,
                    Organization = item.Organisation,
                    Purpose = item.Purpose,
                    Title = item.Purpose,
                    Username = item.Username,
                    Id = item.Id
                },
            };
        }
        public UserDetailsResponse updateUser(string iuserid, UserDetails user)
        {

            UserDetails item;
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                ErrorData errordata = new ErrorData("Given user Id is not an integer");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the userid in the url matches with the user id the body
            if (userid != user.Id)
            {
                ErrorData errordata = new ErrorData("User Id in the request does not match with the resource being accessed.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            //Checking if the user id is empty 
            if (user.Id == 0)
            {
                ErrorData errordata = new ErrorData("User ID in the Request Body cannot be null or Zero");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Making empty field to null value
            #region mapping
          
            if (user.Title == null || user.Title == "")
            {
                user.Title = null;
            }
            if (user.Country == null || user.Country == "")
            {
                user.Country = null;
            }
            if (user.EmailAddress == null || user.EmailAddress == "")
            {
                user.EmailAddress = null;
            }
            if (user.FirstName == null || user.FirstName == "")
            {
                user.FirstName = null;
            }
            if (user.LastName == null || user.LastName == "")
            {
                user.Title = null;
            }
            if (user.Organization == null || user.Organization == "")
            {
                user.Organization = null;
            }
            if (user.Purpose == null || user.Purpose == "")
            {
                user.Purpose = null;
            }
            if (user.Username == null || user.Username == "")
            {
                user.Username = null;
            }
            #endregion

            //Update the details in the repository 
            try
            {
                User newUser = new User()
                {
                    Country = user.Country,
                    Email = user.EmailAddress,
                    FirstName = user.FirstName,
                    Id = user.Id,
                    LastName = user.LastName,
                    Organisation = user.Organization,
                    Purpose = user.Purpose,
                    
                    Title = user.Title,
                    Username = user.Username

                };
                item = userEntity.updateUserById_DAL(userid, newUser);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Updation Failed." + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Creating response message
            outResponse.StatusCode = HttpStatusCode.Accepted;
            Uri location = new Uri(servicePath, "user/" + item.Id.ToString());

            //Returning the response
            return new UserDetailsResponse()
            {
                resource = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri,
                response = item
            };
        }
        public bool deleteUser(string iuserid, UserDeleteContract user)
        {
            bool result = false;
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                ErrorData errordata = new ErrorData("Given user Id is not an integer");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the userid in the url matches with the user id the body
            if (userid != user.Id)
            {
                ErrorData errordata = new ErrorData("User Id in the request does not match with the resource being accessed.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the user id is empty 
            if (user.Id == 0)
            {
                ErrorData errordata = new ErrorData("User ID in the Request Body cannot be null or zero");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            if (user.Password == null || user.Password == "")
            {
                ErrorData errordata = new ErrorData("Password in the Request Body cannot be null or empty");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Perform Delete Operation
            try
            {
                result = userEntity.deleteUser_DAL(userid, user.Password);
                result = true;
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Deletion Failed");
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);

            }

            outResponse.StatusCode = HttpStatusCode.OK;
            return result;
        }
        public bool CheckUserName(string username)
        {
            //Checking if the username exists in the DB
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            outResponse.StatusCode = HttpStatusCode.OK;
            return userEntity.checkUsernameDAL(username);
        }
        public bool ChangePassword(string iuserid, ChangePasswordContract user)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            bool operation = false;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                ErrorData errordata = new ErrorData("Given user Id is not an integer");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the userid in the url matches with the user id the body
            if (userid != user.Id)
            {
                ErrorData errordata = new ErrorData("User Id in the request does not match with the resource being accessed.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the user id is empty 
            if (user.Id == 0)
            {
                ErrorData errordata = new ErrorData("User ID in the Request Body cannot be null or zero");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            if (user.OldPassword == null || user.OldPassword == "" || user.NewPassword == null || user.NewPassword == "")
            {
                ErrorData errordata = new ErrorData("Password in the Request Body cannot be null or empty");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            try
            {
                operation = userEntity.changePassword(user.Id, user.OldPassword, user.NewPassword);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            if (operation)
            {
                outResponse.StatusCode = HttpStatusCode.OK;
                return true;
            }
            outResponse.StatusCode = HttpStatusCode.OK;
            return false;
        }

        #endregion

        #region Devices

        public string changeRepository(string ideviceid, CustomRepo repoinfo)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            if (repoinfo.Url == null || repoinfo.Port == 0 || repoinfo.DBName == null || repoinfo.Url == "" || repoinfo.DBName == "")
            {
                ErrorData errordata = new ErrorData("Connection details cannot be null or empty.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //Checking if the userid in the url matches with the user id the body
            if (deviceid != repoinfo.Id)
            {
                ErrorData errordata = new ErrorData("Device Id in the request does not match with the resource being accessed.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Check if the device id exist
            try
            {
                if (!deviceEntity.idExist_DAL(deviceid))
                {
                    ErrorData errordata = new ErrorData("Device Id does not exists.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
                }
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Unable to retrieve device details." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }
            //construct the uri of the database service 
            string connectionString = String.Format("mongodb://{0}:{1}/{2}", repoinfo.Url, repoinfo.Port.ToString(), repoinfo.DBName);

            //Store the repo information in the repository
            try
            {
                deviceEntity.setConnectionStringAndDB_DAL(deviceid, connectionString, repoinfo.DBName);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Unable to set Repository details." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //return the uri of the database
            return connectionString;
        }
        public CustomRepo getRepository(string ideviceid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            CustomRepo response = new CustomRepo();
            // type casting userid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //Check if the device id exist
            try
            {
                if (!deviceEntity.idExist_DAL(deviceid))
                {
                    ErrorData errordata = new ErrorData("Device Id does not exists.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
                }
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Unable to retrieve device details." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //Gets the repository information from then db
            try
            {
                Dictionary<string, string> result = deviceEntity.getConnectionStringAndDB_DAL(deviceid);
                Uri ConStringUri = new Uri(result["connectionString"]);
                response.Id = deviceid;
                response.Url = ConStringUri.Host;
                response.Port = Convert.ToInt32(ConStringUri.Port);
                response.DBName = result["databaseName"];
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Unable to retrieve Repository Details" + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }
            return response;
        }
        public List<DeviceDetailsResponse> getDevicesList(string iuserid, string privacy)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            List<int> deviceIdCollection;
            List<DeviceDetailsResponse> resobj = new List<DeviceDetailsResponse>();

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //Checking the privacy field
            if (privacy != "public" && privacy != "private" && privacy != "all" && privacy != "shared")
            {
                ErrorData errordata = new ErrorData("Privacy can be only either 'all' or 'public' or 'private' or 'shared'.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotAcceptable);
            }

            //Cheking if the user id exists
            if (!userEntity.checkUserIdDAL(userid))
            {
                ErrorData errordata = new ErrorData("User Id does not exists.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //Retrieve Data
            try
            {
                deviceIdCollection = deviceEntity.getDeviceIdByUserId_DAL(userid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Retrieval Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }

            //checking if any device Ids exists or not
            if (deviceIdCollection.Count == 0)
            {
                ErrorData errordata = new ErrorData("No device exists for this user");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            outResponse.StatusCode = HttpStatusCode.OK;
            //Retrieve the information about each device
            foreach (var device in deviceIdCollection)
            {
                Uri resouseuri = new Uri(servicePath, "devices?userid=" + userid + "&deviceid=" + device);
                Device devdata = deviceEntity.getDeviceById_DAL(userid, device);

                if (privacy == "all")
                {
                    resobj.Add(new DeviceDetailsResponse()
                    {
                        resource = resouseuri,
                        response = devdata
                    });
                }
                if (privacy == "public" && devdata.Privacy == "public")
                {
                    resobj.Add(new DeviceDetailsResponse()
                    {
                        resource = resouseuri,
                        response = devdata
                    });
                }
                if (privacy == "private" && devdata.Privacy == "private")
                {
                    resobj.Add(new DeviceDetailsResponse()
                    {
                        resource = resouseuri,
                        response = devdata
                    });
                }
                //if (privacy == "shared" && devdata.Privacy == "shared")
                //{
                //    resobj.Add(new DeviceDetailsResponse()
                //    {
                //        resource = resouseuri,
                //        response = devdata
                //    });
                //}
            }
            //return the list of devices associated with the user
            return resobj;
        }
        public DeviceDetailsResponse getDevice(int userid, int deviceid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            Device response;

            //Getting the details of the device
            try
            {
                response = deviceEntity.getDeviceById_DAL(userid, deviceid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData(ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }
            outResponse.StatusCode = HttpStatusCode.OK;
            Uri location = new Uri(servicePath, "devices?userid=" + response.User_id + "&deviceid=" + response.Id);

            //returning the response
            return new DeviceDetailsResponse()
            {
                resource = location,
                response = response
            };
        }
        public DeviceDetailsResponse addDevice(Device device)
        {
            Device response;

            //Checking for null fields
            if (device.Name == "" || device.Name == null || device.User_id == 0 || device.Location == null || device.Location == "" ||
                device.Longlat==""||device.Longlat==null)
            {
                ErrorData errordata = new ErrorData("Some mandatory fields are missing in the submitted JSON");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking the privacy field
            if (device.Privacy != "public" && device.Privacy != "private")
            {
                ErrorData errordata = new ErrorData("Privacy can be only either 'public' or 'private'.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotAcceptable);
            }

            //Checking if the device name already exists
            if (deviceEntity.nameExist_DAL(device.User_id, device.Name))
            {
                ErrorData errordata = new ErrorData("Device Name already exist. Please try another unique name.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotAcceptable);
            }

            //set device details fields
            device.Creation_date = System.DateTime.UtcNow;

            //Add the device details
            try
            {
                response = deviceEntity.addDevice_DAL(device);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Device add failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);
            }
            //Change the ip address of the device
            try
            {
                OperationContext context = OperationContext.Current;
                MessageProperties prop = context.IncomingMessageProperties;
                RemoteEndpointMessageProperty endpoint =
                    prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                string ip = endpoint.Address;

                deviceEntity.addIpAddress_DAL(response.Id, ip);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Adding IP failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Creating response message
            Uri location = new Uri(servicePath, "devices?userid=" + response.User_id + "&deviceid=" + response.Id);
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            outResponse.StatusCode = HttpStatusCode.Created;

            //returning the response
            return new DeviceDetailsResponse()
            {
                resource = location,
                response = response
            };
        }
        public DeviceDetailsResponse updateDevice(string ideviceid, Device device)
        {
            Device existingDevice = null;
            Device item;
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting deviceid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                ErrorData errordata = new ErrorData("Given device Id is not an integer");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the userid in the url matches with the user id the body
            if (deviceid != device.Id)
            {
                ErrorData errordata = new ErrorData("Device Id in the request does not match with the resource being accessed.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            //Checking if the user id is empty 
            if (device.Id == 0)
            {
                ErrorData errordata = new ErrorData("Device ID in the Request Body cannot be null or Zero");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            try
            {
                existingDevice = deviceEntity.getDeviceById_DAL(device.User_id, device.Id);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            //Making empty field to null value
            #region mapping
            if (device.Description == null || device.Description == "" || device.Description == existingDevice.Description)
            {
                device.Description = null;
            }
            if (device.Location == null || device.Location == "" || device.Location == existingDevice.Location)
            {
                device.Location = null;
            }
            if (device.Longlat == null || device.Longlat == ""|| device.Longlat == existingDevice.Longlat)
            {
                device.Longlat = null;
            }
            if (device.Name == null || device.Name == ""|| device.Name == existingDevice.Name)
            {
                device.Name = null;
            }
            else
            {
                    if (deviceEntity.nameExist_DAL(device.User_id, device.Name))
                    {
                        ErrorData errordata = new ErrorData("Device name already exists");
                        throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
                    }
                
            }
            if (device.Privacy == null || device.Privacy == "" || device.Privacy == existingDevice.Privacy)
            {
                device.Privacy = null;
            }
            else
            {
                if (device.Privacy != "public" && device.Privacy != "private")
                {
                    ErrorData errordata = new ErrorData("Privacy can be only either 'public' or 'private'.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotAcceptable);
                }
            }
            if (device.Status == null)
            {
                device.Status = false;
            }
            #endregion

            //Update the details in the repository 
            try
            {
                item = deviceEntity.updateDeviceDetails_DAL(device);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Updation Failed." + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Creating response message
            outResponse.StatusCode = HttpStatusCode.Accepted;
            Uri location = new Uri(servicePath, "devices?userid=" + item.User_id + "&deviceid=" + item.Id);

            //Returning the response
            return new DeviceDetailsResponse()
            {
                resource = location,
                response = item
            };

        }
        public bool deleteDevice(string ideviceid)
        {
            bool result = false;
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting userid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                ErrorData errordata = new ErrorData("Given device Id is not an integer");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Check if the device id exist
            if (!deviceEntity.idExist_DAL(deviceid))
            {
                ErrorData errordata = new ErrorData("Given device Id does not exist");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //Perform deletion
            try
            {
                result = deviceEntity.deleteDeviceById_DAL(deviceid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Deletion Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.InternalServerError);

            }
            outResponse.StatusCode = HttpStatusCode.OK;
            return result;

        }
        public bool checkDeviceName(int userid, string devicename)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            //Check if the userid is valid
            if (!userEntity.checkUserIdDAL(userid))
            {
                ErrorData errordata = new ErrorData("Userid does not exist");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NotFound);
            }

            //Check if the device name already exist
            if (deviceEntity.nameExist_DAL(userid, devicename))
            {
                outResponse.StatusCode = HttpStatusCode.OK;
                return true;
            }
            outResponse.StatusCode = HttpStatusCode.OK;
            //if name does not already exist
            return false;
        }

        #endregion

        #region Sensors

        public List<SensorResponse> getSensorsList(int deviceid)
        {

            List<Sensor> sensors;
            List<SensorResponse> response = new List<SensorResponse>();
            //check of the device id exist
            if (!deviceEntity.idExist_DAL(deviceid))
            {
                ErrorData errordata = new ErrorData("Device id does not exists");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            //get the sensors associated with it
            try
            {
                sensors = sensorEntity.getSensorsByDeviceId_DAL(deviceid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Retrieval Failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            if (sensors.Count == 0)
            {
                ErrorData errordata = new ErrorData("There no sensors associated with this Device");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            foreach (var sensor in sensors)
            {
                Uri location = new Uri(servicePath, "sensor/" + sensor.Id.ToString());
                response.Add(new SensorResponse()
                {
                    Resource = location,
                    SensorDetails = sensor
                }
                );
            }

            //response headers
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            outResponse.StatusCode = HttpStatusCode.OK;

            //returning the list of sensors associated with a device
            return response;
        }
        public SensorResponse getSensorsById(string isensorid)
        {

            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            Sensor sensor;

            // type casting sensorid to INT
            int sensorid = -1;
            bool res = Int32.TryParse(isensorid, out sensorid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //Retriving the sensor details
            try
            {
                sensor = sensorEntity.getSensorById_DAL(sensorid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Retrieval Failed." + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Response Message
            outResponse.StatusCode = HttpStatusCode.OK;
            Uri location = new Uri(servicePath, "sensor/" + sensor.Id);

            return new SensorResponse()
            {
                Resource = location,
                SensorDetails = sensor

            };

        }
        public List<NearestSensorsResponse> getNearestSensors(int userid, int sensorid, double radius)
        {
            Sensor sensor;
            Device device;
            List<NearestSensorsResponse> response = new List<NearestSensorsResponse>();


            //Checking if the userid exists
            try
            {
                if (!userEntity.checkUserIdDAL(userid))
                {
                    ErrorData errordata = new ErrorData("UserId Does Not Exist.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
                }
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Retrieval Failed." + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Checking if the sensorid exists
            try
            {
                sensor = sensorEntity.getSensorById_DAL(sensorid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Retrieval Failed." + ex.Message);
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            List<SensorDistance> nearestSensors = sensorEntity.getNearestSensors_DAL(sensorid);
            foreach (var item in nearestSensors)
            {
                Sensor newSensor = sensorEntity.getSensorById_DAL(item.sensorId);
                device = deviceEntity.getDeviceById_DAL(userid,newSensor.Deviceid);
                if(newSensor.Status)
                {
                     response.Add(new NearestSensorsResponse(){Distance=item.distance,Description=device.Description,Location=device.Location,Longlat=device.Longlat,Name=newSensor.Name,Make=newSensor.Make});
                }
            }
            return response;
        }
        public string addSensor(Sensor sensor)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            //Check if the device id is null
            if (sensor.Deviceid == 0)
            {
                throw new ArgumentNullException("DeviceId cannot be null");
            }

            //Check if the device id exists
            if (!deviceEntity.idExist_DAL(sensor.Deviceid))
            {
                throw new ArgumentNullException("DeviceId does not exist");
            }
            //Check if the apikey corresponds to the given apikey

            //check if the mandatory fields of sensor are null
            if (sensor.Name == null || sensor.Type == null || sensor.Make == null || sensor.Interval_measure == null || sensor.Interval_send == null ||
                sensor.Name == "" || sensor.Type == "" || sensor.Make == "" || sensor.Interval_measure == "" || sensor.Interval_send == "")
            {
                throw new ArgumentNullException("Mandatory fields missing");
            }
            //Get the ipaddress of the device from the http request
            OperationContext context = OperationContext.Current;
            MessageProperties messageProperties = context.IncomingMessageProperties;
            RemoteEndpointMessageProperty endpointProperty =
              messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
            string ipaddress = endpointProperty.Address.ToString();

            //Check if the sensor name is unique
            if (!sensorEntity.sensorNameExist_DAL(sensor.Name))
            {
                //add the sensor details
                try
                {
                    Sensor createdSensor = sensorEntity.addSensors_DAL(sensor);
                    monitorSensorEntity.insertOrUpdateAcceessTime_DAL(createdSensor.Id, DateTime.UtcNow.ToString());
                    monitorSensorEntity.setIp_DAL(createdSensor.Id, ipaddress);
                    return createdSensor.Id.ToString();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            //create a response message in the header
            //outResponse.Headers.Add(response_sensor.Name, response_sensor.Id.ToString());
            //return the response message
            return null;
        }
        public string setTrigger(string isensorid, TriggerRequest trigger)
        {

            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            // type casting sensorid to INT
            int sensorid = -1;
            bool res = Int32.TryParse(isensorid, out sensorid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }
            try
            {
                sensorEntity.addOrUpdateLimits_DAL(sensorid, trigger.UpperLimit, trigger.LowerLimit, trigger.Name);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Adding trigger failed."+ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            return "Success";
        }

        public TriggerResponse getTrigger(string isensorid)
        {

            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            TriggerResponse response;

            // type casting sensorid to INT
            int sensorid = -1;
            bool res = Int32.TryParse(isensorid, out sensorid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }
            try
            {
                Limits limit = sensorEntity.getLimits_DAL(sensorid);
                response = new TriggerResponse() { LowerLimit=(double)limit.lower_limit,Name=limit.trigger_name,sensorId=sensorid,UpperLimit=(double)limit.upper_limit};
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Adding trigger failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            return response;
        }
        #endregion

        #region PushNotification

        public SubscriberResponse SubscribeChannel(string iuserid, string isensorid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            SubscriberResponse response = null;
            bool alllowed = false;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            // type casting snesorid to INT
            int sensorid = -1;
            bool res1 = Int32.TryParse(isensorid, out sensorid);
            if (!res1)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //Getting device id of the requested sensor id
            try
            {
                Sensor details = sensorEntity.getSensorById_DAL(sensorid);
                try
                {
                    Device device = deviceEntity.getDeviceById_DAL(userid, details.Deviceid);
                    alllowed = true;
                }
                catch (InvalidOperationException ex)
                {
                    ErrorData errordata = new ErrorData("The device is private. Cannot Access the device." + ex.Message);
                    errordata.StackTrace = ex.StackTrace;
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }
                //Chekcing if the user is allowed to subscribe to sensor data
                if (alllowed)
                {
                    //Generating pusher credentials
                    string Key = "3a96bb88c88f38d16083";
                    string Channel = details.Deviceid.ToString();
                    string Event = details.Id.ToString();

                    //Generating response
                    response = new SubscriberResponse()
                    {
                        Channel = Channel,
                        Event = Event,
                        Key = Key
                    };

                    //Getting ip address of subscriber
                    OperationContext context = OperationContext.Current;
                    MessageProperties prop = context.IncomingMessageProperties;
                    RemoteEndpointMessageProperty endpoint = prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                    string ip = endpoint.Address;

                    //Adding user to subscriber list
                    addSubcriber(new SubscriberRecord()
                    {
                        sensorid = sensorid,
                        userid = userid,
                        ip = ip
                    });
                }
                //User not authorized to access device
                else
                {
                    response = null;
                    ErrorData errordata = new ErrorData("Cannot Subscribe to this device.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }

            }
            catch (Exception ex1)
            {
                ErrorData errordata = new ErrorData("Cannot Access the sensor details." + ex1.Message);
                errordata.StackTrace = ex1.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
            }
            return response;
        }
        public SubscriberResponse SubscribeMissingChannel(string iuserid, string ideviceid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            SubscriberResponse response = null;
            bool alllowed = false;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            // type casting snesorid to INT
            int deviceid = -1;
            bool res1 = Int32.TryParse(ideviceid, out deviceid);
            if (!res1)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //Getting device id of the requested sensor id
            try
            {
                try
                {
                    Device device = deviceEntity.getDeviceById_DAL(userid, deviceid);
                    alllowed = true;
                }
                catch (InvalidOperationException ex)
                {
                    ErrorData errordata = new ErrorData("The device is private. Cannot Access the device." + ex.Message);
                    errordata.StackTrace = ex.StackTrace;
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }
                //Chekcing if the user is allowed to subscribe to sensor data
                if (alllowed)
                {
                    //Generating pusher credentials
                    string Key = "3a96bb88c88f38d16083";
                    string Channel = deviceid.ToString();
                    string Event = "gpsLocation";

                    //Generating response
                    response = new SubscriberResponse()
                    {
                        Channel = Channel,
                        Event = Event,
                        Key = Key
                    };
                }
                //User not authorized to access device
                else
                {
                    response = null;
                    ErrorData errordata = new ErrorData("Cannot Subscribe to this device.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }
            }
            catch (Exception ex1)
            {
                ErrorData errordata = new ErrorData("Cannot Access the sensor details." + ex1.Message);
                errordata.StackTrace = ex1.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
            }
            return response;
        }
        public List<int> allSubscribedSensors()
        {
            List<int> sensors = new List<int>();

            foreach (var sub in subscriberList.getSubscriberList())
            {
                if (!sensors.Contains(sub.sensorid))
                {
                    sensors.Add(sub.sensorid);
                }
            }
            if (sensors.Count == 0)
            {
                return null;
            }
            return sensors;
        }
        public List<SubscribedUsers> SubscribedUsers(string iuserid, string isensorid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            List<SubscribedUsers> response = new List<SubscribedUsers>();
            bool alllowed = false;

            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }
            // type casting snesorid to INT
            int sensorid = -1;
            bool res1 = Int32.TryParse(isensorid, out sensorid);
            if (!res1)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //check if the given userid is the owner of sensor
            try
            {
                //getting the device id of the device
                Sensor details = sensorEntity.getSensorById_DAL(sensorid);
                try
                {
                    //getting the userid of the device
                    Device device = deviceEntity.getDeviceById_DAL(userid, details.Deviceid);
                    if (device.User_id == userid)
                    {
                        alllowed = true;
                    }
                }
                catch (InvalidOperationException ex)
                {
                    ErrorData errordata = new ErrorData("The device is private. Cannot Access the device." + ex.Message);
                    errordata.StackTrace = ex.StackTrace;
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }
                if (alllowed)
                {
                    List<SubscriberRecord> sublist = subscriberList.getSubscriberList();

                    //get the subscribers list
                    foreach (var sub in sublist)
                    {
                        if (sub.sensorid == sensorid)
                        {
                            UserDetails user = userEntity.getUserById_DAL(sub.userid);
                            response.Add(new SubscribedUsers()
                            {
                                FullName = user.FirstName + " " + user.LastName,
                                Location = user.Country,
                                Organisation = user.Organization,
                                Purpose = user.Purpose
                            });
                        }
                        else
                        {
                            ErrorData errordata = new ErrorData("No users subscribed to this sensor");
                            throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                        }
                    }
                }
                //User not authorized to access device
                else
                {
                    response = null;
                    ErrorData errordata = new ErrorData("Cannot Subscribe to this device.");
                    throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
                }
            }
            catch (Exception ex1)
            {
                ErrorData errordata = new ErrorData("Cannot Access the sensor details." + ex1.Message);
                errordata.StackTrace = ex1.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
            }
            return response;
        }
        public bool UnSubscribeChannel(string iuserid, string isensorid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            bool response = false;
            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return false;
            }
            // type casting snesorid to INT
            int sensorid = -1;
            bool res1 = Int32.TryParse(isensorid, out sensorid);
            if (!res1)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return false;
            }
            SubscriberRecord delsubscriber = new SubscriberRecord() { userid = userid, sensorid = sensorid };
            //Check if subscriber exists
            if (SubscriberList.Contains(delsubscriber))
            {
                removeSubcriber(delsubscriber);
                response = true;
            }
            else if (subscriberList.getSubscriberList().Contains(delsubscriber))
            {
                subscriberList.removeSubscriber(delsubscriber);
                response = true;

            }
            else
            {
                ErrorData errordata = new ErrorData("No users subscribed to this sensor");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.NoContent);
            }
            return response;
        }

        #endregion

        #region Shared Devices

        public bool sharePrivateDevice(string ideviceid, ShareDeviceContract shareinfo)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            int userid;
            bool alllowed = false;

            // type casting userid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return false;
            }

            //Check if the device id exists
            if (!deviceEntity.idExist_DAL(deviceid))
            {
                ErrorData errordata = new ErrorData("Device id does not exist");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Check if the sharer username exists
            if (!userEntity.checkUsernameDAL(shareinfo.SharerUsername))
            {
                ErrorData errordata = new ErrorData("Username trying to share device with does not exist.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Check if the given user is the owner of the device
            try
            {
                deviceEntity.getDeviceById_DAL(shareinfo.OwnerId, deviceid);
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Cannot retrieve the details of the device." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);

            }

            //Make the device shared with the given username
            //Get the userid of the given username
            try
            {
                userid = userEntity.getUserIdByUsername_DAL(shareinfo.SharerUsername);
                sharedEntity.shareDeviceWithUser_DAL(deviceid, userid);
                alllowed = true;

            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Username trying to share device with does not exist." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //send response
            return alllowed;
        }
        public bool removeSharedPrivateDevice(string ideviceid, ShareDeviceContract shareinfo)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            bool success = false;

            // type casting userid to INT
            int deviceid = -1;
            bool res = Int32.TryParse(ideviceid, out deviceid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return false;
            }

            //Check if the device id exists
            if (!deviceEntity.idExist_DAL(deviceid))
            {
                ErrorData errordata = new ErrorData("Device id does not exist");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            //Get the userid of the given username
            try
            {
                int userid = userEntity.getUserIdByUsername_DAL(shareinfo.SharerUsername);
                sharedEntity.removeSharedDevice(deviceid, userid);
                success = true;
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Username trying to share device with does not exist." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            return success;
        }

        #endregion

        #region Notification
        
        public List<NotificationResponse> getlostDevices(string iuserid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            List<NotificationResponse> response = new List<NotificationResponse>();
            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //check if the userid exist
            if (!userEntity.checkUserIdDAL(userid))
            {
                ErrorData errordata = new ErrorData("UserId does not exist.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            //get the list of lost devices
            List<Notification> result = notificationEntity.getNotificationsByFilter_DAL(userid, "lost");
            foreach(var notification in result){
                var devicename = deviceEntity.getDeviceById_DAL(notification.userId, notification.deviceId).Name;
                response.Add(new NotificationResponse() {sensorId=notification.sensorId,notificationId=notification.id,deviceId=notification.deviceId,deviceName=devicename,reason=notification.reason});
            }
            return response ;
        }
        public List<NotificationResponse> getNotification(string iuserid)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            List<NotificationResponse> response = new List<NotificationResponse>();
            // type casting userid to INT
            int userid = -1;
            bool res = Int32.TryParse(iuserid, out userid);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //check if the userid exist
            if (!userEntity.checkUserIdDAL(userid))
            {
                ErrorData errordata = new ErrorData("UserId does not exist.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
     
            //get the list of all notifications
            List<Notification> result = notificationEntity.getNotifications_DAL(userid);
            foreach (var notification in result)
            {
                var devicename = deviceEntity.getDeviceById_DAL(notification.userId, notification.deviceId).Name;
                response.Add(new NotificationResponse() {sensorId=notification.sensorId,notificationId=notification.id, deviceId = notification.deviceId, deviceName = devicename, reason = notification.reason });
            }
            return response;
        }
        public string removeNotification(string inotificationId)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;
            List<NotificationResponse> response = new List<NotificationResponse>();
            // type casting userid to INT
            int notificationId = -1;
            bool res = Int32.TryParse(inotificationId, out notificationId);
            if (!res)
            {
                outResponse.StatusCode = HttpStatusCode.BadRequest;
                outResponse.StatusDescription = "Not an Integer";
                return null;
            }

            //remove the notifications
            notificationEntity.removeNotification_DAL(notificationId);
          
            return "Success";
        }

        #endregion





    }
}
